package com.yanqu.road.server.gameplayer.module.activity.zhounianturntable;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.zhounianturntable.ZhouNianTurntableConfig;
import com.yanqu.road.entity.activity.zhounianturntable.ZhouNianTurntableData;
import com.yanqu.road.entity.activity.zhounianturntable.ZhouNianTurntableItem;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.LogZhouNianTurntableChoose;
import com.yanqu.road.entity.log.LogZhouNianTurntableDraw;
import com.yanqu.road.logic.bussiness.activity.ZhouNianTurntableBusiness;
import com.yanqu.road.pb.activity.ZhouNianTurntableProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.zhounianturntable.ZhouNianTurntableActivity;
import com.yanqu.road.server.manger.activity.zhounianturntable.ZhouNianTurntableMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.pb.PlayerPb;
import com.yanqu.road.server.pb.ZhouNianTurntablePb;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.CrossProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

public class ZhouNianTurntableModule extends GeneralModule {

    private Map<Integer, ZhouNianTurntableData> userDataMap = new ConcurrentHashMap<>();

    public RandomHelper random = new RandomHelper();

    public ZhouNianTurntableModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        if (SystemOpenMgr.systemOpen(player, eSystemId.ZhouNianTurntable.getValue())) {
            ZhouNianTurntableMgr.getActivityMap().values().forEach(zhouNianTurntableActivity -> {
                ActivityInfo activityInfo = zhouNianTurntableActivity.getActivityInfo();
                if (ActivityMgr.activityInShowTime(activityInfo)) {
                    ZhouNianTurntableData zhouNianTurntableData = ZhouNianTurntableBusiness.getZhouNianTurntableData(activityInfo.getActivityId(), player.getUserId());
                    if (zhouNianTurntableData != null) {
                        userDataMap.put(activityInfo.getActivityId(), zhouNianTurntableData);
                    }
                }
            });

        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        for (ZhouNianTurntableData userData : userDataMap.values()) {
            if (userData.isInsertOption()) {
                ZhouNianTurntableBusiness.addZhouNianTurntableData(userData);
            } else if (userData.isUpdateOption()) {
                ZhouNianTurntableBusiness.updateZhouNianTurntableData(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {

    }

    @Override
    public void loginSendMsg() {
        if (SystemOpenMgr.systemOpen(player, eSystemId.ZhouNianTurntable.getValue())) {
            syncConfig();
            initUserData();
            syncData();
        }
    }

    public void syncConfig() {
        Map<Integer, ZhouNianTurntableActivity> activityMap = ZhouNianTurntableMgr.getActivityMap();
        if (activityMap.size() == 0) {
            return;
        }
        ZhouNianTurntableProto.TurntableSyncConfigRespMsg.Builder builder = ZhouNianTurntablePb.parseTurntableSyncConfigRespMsg();
        player.sendPacket(ClientProtocol.U_ZHOUNIAN_TURNTABLE_SYNC_CONFIG, builder);
    }


    public synchronized void initUserData() {
       ZhouNianTurntableMgr.getActivityMap().values().forEach(zhouNianTurntableActivity -> {
           ActivityInfo activityInfo = zhouNianTurntableActivity.getActivityInfo();
           if (activityInfo == null) {
               return;
           }
           if (userDataMap.get(activityInfo.getActivityId()) != null && userDataMap.get(activityInfo.getActivityId()).getActivityId() == activityInfo.getActivityId()) {
               return;
           }

           ZhouNianTurntableData data = new ZhouNianTurntableData();
           data.setActivityId(activityInfo.getActivityId());
           data.setUserId(player.getUserId());
           data.setItems(new ArrayList<>());
           data.setChooseInfoMap(new ConcurrentHashMap<>());
           data.setInsertOption();
           userDataMap.put(activityInfo.getActivityId(), data);
       });
    }

    public void syncData() {
        ActivityInfo activityInfo = getInTimeOrPreviousActivity();
        if (activityInfo == null || userDataMap.get(activityInfo.getActivityId()) == null) {
            return;
        }
        // 同步数据
        player.sendPacket(ClientProtocol.U_ZHOUNIAN_TURNTABLE_DATA, getTurntableInfo());
    }

    public void initSystem() {
        if (SystemOpenMgr.systemOpen(player, eSystemId.ZhouNianTurntable.getValue())) {
            initUserData();
            syncConfig();
            syncData();
        }
    }

    /**
     * 获取当前进行的活动,如果未在进行中则获取上一轮的活动(同步数据时用到)
     */
    public ActivityInfo getInTimeOrPreviousActivity() {
        ActivityInfo activityInfo = ZhouNianTurntableMgr.getInTimeActivityInfo();
        if (activityInfo == null) {
            // 没有进行中的获取上一轮的活动
            List<ActivityInfo> activityList = new ArrayList<>();
            Map<Integer, ZhouNianTurntableActivity> activityMap = ZhouNianTurntableMgr.getActivityMap();
            for (ZhouNianTurntableActivity zhouNianTurntableActivity : activityMap.values()) {
                if (zhouNianTurntableActivity.getActivityInfo() != null) {
                    activityList.add(zhouNianTurntableActivity.getActivityInfo());
                }
            }
            // 排序
            activityList.sort(Comparator.comparingInt(ActivityInfo::getChildType));
            long nowTime = System.currentTimeMillis() / 1000;
            for (ActivityInfo info : activityList) {
                if (info.getEndTime() < nowTime) {
                    activityInfo = info;
                }
            }
        }
        return activityInfo;
    }

    /**
     * 获取宝盘信息
     */
    public ZhouNianTurntableProto.TurntableDataRespMsg.Builder getTurntableInfo() {
        ZhouNianTurntableProto.TurntableDataRespMsg.Builder respMsg = ZhouNianTurntableProto.TurntableDataRespMsg.newBuilder();
        ActivityInfo activityInfo = getInTimeOrPreviousActivity();
        // 获取当前用户的信息
        if (activityInfo == null || userDataMap.get(activityInfo.getActivityId()) == null) {
            return respMsg;
        }
        respMsg.setTurntableData(ZhouNianTurntablePb.createTurntableData(userDataMap.get(activityInfo.getActivityId())));
        return respMsg;
    }



    /**
     * 选择奖励
     */
    public int chooseReward(String chooseIds) {
        ActivityInfo activityInfo = ZhouNianTurntableMgr.getInTimeActivityInfo();
        if (activityInfo == null) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_NO_OPEN;
        }
        ZhouNianTurntableActivity zhouNianTurntableActivity = ZhouNianTurntableMgr.activityMap.get(activityInfo.getActivityId());
        if (zhouNianTurntableActivity == null) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_NO_OPEN;
        }
        // 获取当前用户的信息
        if (userDataMap.get(activityInfo.getActivityId()) == null) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_NO_UNLOCK;
        }
        // 判断是否可自选,需要抽完第一档次奖励
        if (!checkFirstGearReward(activityInfo.getActivityId())) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_LEFT_REWARD;
        }
        // 判断数量是否合法
        if (!checkChooseNum(activityInfo.getActivityId(), chooseIds)) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_CHOOSE_PARAM_INVALID;
        }

        List<ZhouNianTurntableItem> items = new ArrayList<>();
        String[] gears = chooseIds.split("\\|");
        for (String gear : gears) {
            String[] gearSplit = gear.split("=");
            if (gearSplit.length < 2) {
                return GameErrorCode.E_ZHOUNIAN_TURNTABLE_CHOOSE_PARAM_INVALID;
            }
            int gearId = Integer.parseInt(gearSplit[0]);
            if (!zhouNianTurntableActivity.configMap.containsKey(gearId)) {
                // 档位id不存在
                return GameErrorCode.E_ZHOUNIAN_TURNTABLE_GEAR_ID_NOT_EXIST;
            }
            // 奖励列表
            ZhouNianTurntableConfig turntableConfig = zhouNianTurntableActivity.configMap.get(gearId);
            String reward = turntableConfig.getReward();
            String[] rewardList = reward.split("\\|");
            String[] idxList = gearSplit[1].split(",");
            if (idxList.length != turntableConfig.getSelectNum()) {
                // 选择数量有误
                return GameErrorCode.E_ZHOUNIAN_TURNTABLE_CHOOSE_NUM_INVALID;
            }
            for (String idxStr : idxList) {
                int idx = Integer.parseInt(idxStr);
                if (idx < 0 || idx >= rewardList.length) {
                    // 索引有误
                    return GameErrorCode.E_ZHOUNIAN_TURNTABLE_INDEX_INVALID;
                }
                if (!checkChooseLimit(activityInfo.getActivityId(), gearId, idx)) {
                    // 选择次数超过限制
                    return GameErrorCode.E_ZHOUNIAN_TURNTABLE_CHOOSE_LIMIT;
                }
                addChooseLimit(activityInfo.getActivityId(), gearId, idx);
                String[] split = rewardList[idx].split("=");
                int rewardId = Integer.parseInt(split[0]);
                String[] params = split[1].split(";");
                BigInteger rewardCount = BigInteger.valueOf(Long.parseLong(params[0]));
                int drawTimesLimit = Integer.parseInt(params[1]);
                // 添加奖励
                items.add(new ZhouNianTurntableItem(items.size(), PropertyHelper.parsePropertyToString(new Property(rewardId, rewardCount)), drawTimesLimit, gearId));
            }
        }
        userDataMap.get(activityInfo.getActivityId()).setItems(items);

        // 选择的奖励
        String chooseReward = userDataMap.get(activityInfo.getActivityId()).getItems().stream()
                .map(item -> item.getGear() + ":" + item.getReward())
                .collect(Collectors.joining(";"));
        // 记录日志
        AutoLogMgr.add(new LogZhouNianTurntableChoose(
                player.getUserId(),
                activityInfo.getActivityId(),
                activityInfo.getChildType(),
                chooseReward
        ));
        ZhouNianTurntableProto.TurntableChooseRewardRespMsg.Builder respMsg = ZhouNianTurntableProto.TurntableChooseRewardRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setTurntableData(ZhouNianTurntablePb.createTurntableData(userDataMap.get(activityInfo.getActivityId())));
        player.sendPacket(Protocol.U_ZHOUNIAN_TURNTABLE_CHOOSE_REWARD, respMsg);
        return 0;
    }

    /**
     * 检查选择的是否超过限制
     */
    private boolean checkChooseLimit(int activityId, int gearId, int idx) {
        ZhouNianTurntableActivity zhouNianTurntableActivity = ZhouNianTurntableMgr.activityMap.get(activityId);
        String reward = zhouNianTurntableActivity.configMap.get(gearId).getReward();
        String[] rewardList = reward.split("\\|");
        String[] split = rewardList[idx].split("=");
        String[] params = split[1].split(";");
        // 选择次数限制
        int chooseTimesLimit = Integer.parseInt(params[2]);
        // 不限制
        return chooseTimesLimit == -1 || userDataMap.get(activityId).getChooseInfoMap().getOrDefault(gearId + "," + idx, 0) < chooseTimesLimit;
    }

    /**
     * 添加选择的限制
     */
    private void addChooseLimit(int activityId, int gearId, int idx) {
        String key = gearId + "," + idx;
        if (userDataMap.get(activityId).getChooseInfoMap().containsKey(key)) {
            userDataMap.get(activityId).getChooseInfoMap().put(key, userDataMap.get(activityId).getChooseInfoMap().get(key) + 1);
        } else {
            userDataMap.get(activityId).getChooseInfoMap().put(key, 1);
        }
        // 更新数据库
        userDataMap.get(activityId).setUpdateOption();
    }


    /**
     * 抽奖
     */
    public int drawReward(int type) {
        ActivityInfo activityInfo = ZhouNianTurntableMgr.getInTimeActivityInfo();
        if (activityInfo == null) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_NO_OPEN;
        }
        ZhouNianTurntableActivity zhouNianTurntableActivity = ZhouNianTurntableMgr.activityMap.get(activityInfo.getActivityId());
        if (zhouNianTurntableActivity == null) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_NO_OPEN;
        }
        // 获取当前用户的信息
        if (userDataMap.get(activityInfo.getActivityId()) == null) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_NO_UNLOCK;
        }
        // 判断是否全部抽完
        int leftDrawTimes = getLeftDrawTimes(activityInfo.getActivityId());
        if (leftDrawTimes <= 0) {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_NO_REWARD;
        }
        ZhouNianTurntableProto.TurntableRewardRespMsg.Builder respMsg = ZhouNianTurntableProto.TurntableRewardRespMsg.newBuilder();
        List<Property> rewardList = new ArrayList<>();
        Property reward = new Property();
        int drawTimes = 1;
        if (type == 0) {
            // 单抽
            // 消耗道具
            if (!player.getModule(CurrencyModule.class).removeCurrency(new Property(zhouNianTurntableActivity.ZHOUNIAN_TURNTABLE_ITEM_ID, zhouNianTurntableActivity.ZHOUNIAN_TURNTABLE_ITEM_COUNT), eLogMoneyType.ZhouNianTurntable, eLogMoneyType.ZhouNianTurntableOneCost)) {
                return GameErrorCode.E_ZHOUNIAN_TURNTABLE_ITEM_NO_ENOUGH;
            }
        } else if (type == 1) {
            // 十连抽
            drawTimes = Math.min(leftDrawTimes, 10);
            // 消耗道具
            if (!player.getModule(CurrencyModule.class).removeCurrency(new Property(zhouNianTurntableActivity.ZHOUNIAN_TURNTABLE_ITEM_ID, BigInteger.valueOf(drawTimes).multiply(BigInteger.valueOf(zhouNianTurntableActivity.ZHOUNIAN_TURNTABLE_ITEM_COUNT))), eLogMoneyType.ZhouNianTurntable, eLogMoneyType.ZhouNianTurntableTenCost)) {
                return GameErrorCode.E_ZHOUNIAN_TURNTABLE_ITEM_NO_ENOUGH;
            }
        } else {
            return GameErrorCode.E_ZHOUNIAN_TURNTABLE_TYPE_INVALID;
        }
        List<Integer> drawIndexs = new ArrayList<>();
        for (int i = 0; i < drawTimes; i++) {
            drawIndexs.add(draw(activityInfo.getActivityId()));
        }
        AtomicLong score = new AtomicLong();
        drawIndexs.forEach(drawIndex -> userDataMap.get(activityInfo.getActivityId()).getItems().stream()
                .filter(item -> item.getIndex() == drawIndex)
                .findFirst()
                .ifPresent(item -> {
                    Property property = PropertyHelper.parseStringToProperty(item.getReward());
                    reward.addProperty(property);
                    rewardList.add(property);
                    // 获得的积分
                    score.addAndGet(zhouNianTurntableActivity.configMap.get(item.getGear()).getScore());
                }));
        userDataMap.get(activityInfo.getActivityId()).setUpdateOption();
        // 获得道具
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.ZhouNianTurntable, eLogMoneyType.ZhouNianTurntableDrawGet);
        player.notifyListener(eGamePlayerEventType.ZhouNianTurntableTimes.getValue(), BigInteger.valueOf(drawTimes));
        // 积分排行榜
        player.notifyListener(eGamePlayerEventType.ZhouNianTurntableScoreRank.getValue(), BigInteger.valueOf(score.get()));
        // 添加记录
        AutoLogMgr.add(new LogZhouNianTurntableDraw(
                player.getUserId(),
                activityInfo.getActivityId(),
                activityInfo.getChildType(),
                type,
                PropertyHelper.parsePropertyToString(reward)
        ));
        respMsg.setRet(0);
        for (Property property : rewardList) {
            respMsg.addReward(PropertyHelper.parsePropertyToString(property));
        }
        respMsg.addAllDrawIndex(drawIndexs);
        respMsg.setScore(score.get());
        respMsg.setTurntableData(ZhouNianTurntablePb.createTurntableData(userDataMap.get(activityInfo.getActivityId())));
        player.sendPacket(Protocol.U_ZHOUNIAN_TURNTABLE_DRAW_REWARD, respMsg);
        return 0;
    }

    /**
     * 单抽
     */
    private int draw(int activityId) {
        // 总权重
        int totalWeight = 0;
        // 抽奖的索引
        int index = -1;
        List<ZhouNianTurntableItem> turntableItemList = userDataMap.get(activityId).getItems();
        for (ZhouNianTurntableItem item : turntableItemList) {
            if (item.getLeftDrawTimes() > 0) {
                totalWeight += getWeight(activityId, item.getGear());
            }
        }
        int randomValue = random.next(0, totalWeight);
        for (ZhouNianTurntableItem item : turntableItemList) {
            if (item.getLeftDrawTimes() > 0) {
                if (randomValue < getWeight(activityId, item.getGear())) {
                    index = item.getIndex();
                    item.setLeftDrawTimes(item.getLeftDrawTimes() - 1);
                    // 公告
                    if (isNotice(activityId, item.getGear())) {
                        // 上公告
                        ZhouNianTurntableProto.CrossTurntableRecordUploadRecordReqMsg.Builder recordBuilder = ZhouNianTurntableProto.CrossTurntableRecordUploadRecordReqMsg.newBuilder();
                        recordBuilder.setActivityId(activityId);
                        recordBuilder.setPlayer(PlayerPb.parsePlayerBaseTempMsg(player.getUserInfo()));
                        recordBuilder.setReward(item.getReward());
                        player.sendPacket(CrossProtocol.C_ZHOUNIAN_TURNTABLE_ACTIVITY_UPLOAD_RECORD, recordBuilder);
                    }
                    break;
                }
                randomValue -= getWeight(activityId, item.getGear());
            }
        }

        return index;
    }

    /**
     * 判断第一档次是否都抽取完成
     */
    public boolean checkFirstGearReward(int activityId) {
        for (ZhouNianTurntableItem item : userDataMap.get(activityId).getItems()) {
            if (item.getGear() == 1 && item.getLeftDrawTimes() > 0) {
                return false;
            }
        }
        return true;
    }


    /**
     * 剩余可抽取的数量
     */
    public int getLeftDrawTimes(int activityId) {
        int leftDrawTimes = 0;
        for (ZhouNianTurntableItem item : userDataMap.get(activityId).getItems()) {
            if (item.getLeftDrawTimes() > 0) {
                leftDrawTimes += item.getLeftDrawTimes();
            }
        }
        return leftDrawTimes;
    }

    /**
     * 获取权重
     */
    public int getWeight(int activityId, int gear) {
        return ZhouNianTurntableMgr.activityMap.get(activityId).configMap.containsKey(gear) ? ZhouNianTurntableMgr.activityMap.get(activityId).configMap.get(gear).getWeight() : 0;
    }

    /**
     * 是否公告
     */
    public boolean isNotice(int activityId, int gear) {
        return ZhouNianTurntableMgr.activityMap.get(activityId).configMap.containsKey(gear) && (ZhouNianTurntableMgr.activityMap.get(activityId).configMap.get(gear).getAnnounce() == 1);
    }

    /**
     * 检查选择的数量
     */
    public boolean checkChooseNum(int activityId, String chooseIds) {
        int chooseCnt = 0;
        String[] gears = chooseIds.split("\\|");
        for (String gear : gears) {
            String[] gearSplit = gear.split("=");
            if (gearSplit.length < 2) {
                continue;
            }
            String[] idxList = gearSplit[1].split(",");
            chooseCnt += idxList.length;
        }
        int configCnt = ZhouNianTurntableMgr.activityMap.get(activityId).configMap.values().stream().mapToInt(ZhouNianTurntableConfig::getSelectNum).sum();
        return chooseCnt == configCnt;
    }

}
